package com.restphp.java.hashdb.dcs.server;

import com.restphp.java.hashdb.dcs.HashDbClusterConfig;
import com.restphp.java.hashdb.dcs.constant.IPType;
import com.restphp.java.hashdb.dcs.po.ClusterNode;
import com.restphp.java.hashdb.dcs.utils.ClusterNodeUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;

import java.nio.charset.Charset;

/**
 * 群集服务.
 * Created by sofical on 2020/8/11.
 */
public class HashDbClusterServer {
    private HashDbClusterConfig clusterConfig;
    public HashDbClusterServer(HashDbClusterConfig clusterConfig) {
        this.clusterConfig = clusterConfig;
    }

    /**
     * 启动群集服务.
     */
    public void startup() {
        // 群集里是否有本地.
        for (ClusterNode node : this.clusterConfig.nodeList()) {
            String ip = ClusterNodeUtils.getHostAddress(node);
            Boolean isLocal = ClusterNodeUtils.isLocal(ip, node.getIpType());

            if (isLocal) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        start(node, ip);
                    }
                }).start();
            }
        }
    }

    private static Boolean running = false;

    /**
     * 开启监听服务.
     * @param node 群集节点.
     * @param ip 实际IP地址.
     */
    private static void start(ClusterNode node, String ip) {
        if (running) {
            return;
        }
        running = true;
        EventLoopGroup workGroup = new NioEventLoopGroup();
        EventLoopGroup boosGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(boosGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(node.getPort())
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //System.out.print("接收到客户消息");

                            socketChannel.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
                            socketChannel.pipeline().addLast(new HashDbClusterEchoServerHandler());
                            socketChannel.pipeline().addLast(new ByteArrayEncoder());
                        }
                    });
            //服务器异步创建绑定
            ChannelFuture cf = sb.bind(ip, node.getPort()).sync();
            System.out.println(HashDbClusterServer.class + " 启动正在监听： " + cf.channel().localAddress());
            //关闭服务器通道
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                workGroup.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                boosGroup.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /*public static void main(String[] args) {
        ClusterNode node = new ClusterNode();
        String ip = "192.168.8.116";
        node.setIpType(IPType.IPV4);
        node.setAddress(ip);
        node.setPort(889);

        start(node, ip);
    }*/
}
